/*
 * This file is part of shared-drawing.
 * shared-drawing is free software: you can redistribute it and/or modify it 
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option )
 * any later version. shared-drawing is distributed in the hope that it will
 * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details.
 * You should have received a copy of the GNU General Public License along with 
 * shared-drawing. If not, seehttp://www.gnu.org/licenses/.
 */
package SharedDrawing;

import common.XmlConstants;
import java.awt.Color;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;
import javax.swing.JOptionPane;

/**
 * pages is the list of all (shown in the tabbed pane or not) page
 * 
 */
public class Pages {

    private Integer lastMessage = new Integer(0);
    private String lastemitter = new String();
    private HashMap<Integer, Page> pages = new HashMap();
    private String primitiveType;
    private boolean selectionMode;
    private int primitiveWidth;
    private boolean primitiveFilled;
    private PrimitivesFactory factory = new PrimitivesFactory("primitives");
    private static Pages instance;
    private Color colorSelected;
    private Color borderColorSelected;
    private long nextId;
    /*
     * because of the bug ID #6880336 in java
     * the UI can't have several SwingWorkers, so just one worker exists and
     * it takes actions as parameters, so instead of creating another SW and send
     * it pages, the waiting pages are pushed here, then the SW will consumm pages
     * from here
     */
    private Stack<Page> waitingPages;
    
    private Pages()
    {
        
            factory = new PrimitivesFactory("shapes");
            if(factory.isClassesEmpty())
            {
                    System.exit(-1);
            }
            else
            {
                    primitiveType = factory.getClassName(0);
            }
            
            selectionMode = true;
            colorSelected = Color.WHITE;
            borderColorSelected = Color.BLACK;
            ArrayList<Class> fc = factory.getClasses();
            waitingPages = new Stack();
            nextId = 0;
            primitiveWidth = 1;
            setPrimitiveFilled(false);
    }
    
    public static Pages getInstance()
    {
        if(instance == null)
            instance = new Pages();
        
        return instance;
    }
    
    boolean getSelectionMode() {
        return selectionMode;
    }

    public void setSelectionMode(boolean selectionMode) {
        this.selectionMode = selectionMode;
    }

    public Color getBorderColorSelected() {
        return borderColorSelected;
    }

    public Color getColorSelected() {
        return colorSelected;
    }

    public void setBorderColorSelected(Color borderColorSelected) {
        this.borderColorSelected = borderColorSelected;
    }

    public void setColorSelected(Color colorSelected) {
        this.colorSelected = colorSelected;
    }

    public String getPrimitiveType() {
        return primitiveType;
    }

    public int getPrimitiveWidth() {
        return primitiveWidth;
    }

    public void setPrimitiveType(String primitiveType) {
        this.primitiveType = primitiveType;
    }

    public void setPrimitiveWidth(int primitiveWidth) {
        this.primitiveWidth = primitiveWidth;
    }

    public PrimitivesFactory getFactory() {
        return factory;
    }
    
    /**
     * 
     * @param drawingId
     * @param old 
     * when a user creates a page, this one will have an id to identify
     * it, when the server get it, it will reassign an id and so,
     * replace the old one given by the client's software by the new given
     * by the server
     */
    void setPage(Integer drawingId, Integer old) {
        pages.get(old).setId(drawingId);
    }

    public HashMap<Integer, Page> getPages() {
        return pages;
    }

    /**
     * get a page from its name
     * @param name the name of of the choosen page
     * @return the page
     */
    public Page getPage(String name) {
        for(Integer current : pages.keySet())
       {
           if(pages.get(current).getName().equals(name))
           {
               return(pages.get(current));
           }
       }
       return null;
    }
    
    /**
     * call draw on the choosen page
     * @param pageId the choosen page
     * @param wgContent the thing to draw
     */
    public void draw(Integer pageId, List<ShapeContent> Contents)
    {
        pages.get(pageId).draw(Contents);
    }
    
    public Page createPageFromUpload(Integer pageId, String name, String emitter)
    {
        for(Page existing : pages.values())
        {
            if(existing.getName().equals(name))
            {
                Object[] options = {"rename",
                "don't upload"};
                int n = JOptionPane.showOptionDialog(SharedDrawingUI.getInstance(),
                    "A page with the same name already exists\n"+
                    "do you want to rename the uploaded page ?",
                    "ouch",
                    JOptionPane.YES_NO_OPTION,
                    JOptionPane.QUESTION_MESSAGE,
                    null,
                    options,
                    options[0]);
                if(n == JOptionPane.YES_OPTION)
                {
                    //rename the page
                    String s = JOptionPane.showInputDialog(
                            SharedDrawingUI.getInstance(), 
                            "please enter the new name of the page", 
                            name+"_bis");
                    if(s!=null && s.length()>0)
                    {
                        return createPageFromUpload(pageId, s, emitter);
                    }
                    else
                    {
                        return null;
                    }
                }
                else
                {
                    return null;
                }
            }
        }
        return createPage(pageId, name, emitter);
    }
    
    /**
     * calls createPage on the given identifier's page and
     * called when uploading
     * @param pageId the identifier of the new page
     * @param name its name
     * @param emitter the user who created the page
     */
    public Page createPage(Integer pageId, String name, String emitter)
    {
        Page newOne = new Page(pageId, name, emitter);
        pages.put(pageId, newOne);
        waitingPages.add(newOne);
        Action action = new Action(XmlConstants.createPage);
        SharedDrawingUI.getInstance().getWorker().push(action);
        return newOne;
    }
    
    /**
     * called when another user creates a page
     * @param pageId
     * @param name
     * @param emitter
     * @return 
     */
    public Page createPageFromUser(Integer pageId, String name, String emitter)
    {
        Page page = createPage(pageId, name, emitter);
        page.incPageView(emitter);
        return page;
    }
    
    /**
     * called when a user creates a page
     * @param name
     * @return 
     */
    public Page createPage(String name)
    {
        Page page = createPage(Integer.parseInt(getFreeNumber()),
                name, 
                ConnexionManager.getInstance().getUserId());
        page.incPageView(ConnexionManager.getInstance().getUserId());
        sendPage(page);
        return page;
    }
    
    public void sendPage(Page page)
    {
        List<Page> pagesToSend = new ArrayList();
        pagesToSend.add(page);
        XmlGenerator.sendXml(pagesToSend);
    }
    
    /**
     * kill the given page
     * @param pageId the given page
     * @param emitter the user who killed the page
     */
    public void deletePage(Integer pageId, String emitter)
    {
        pages.clear();
    }
    
    /**
     * calls incPageView on the given page
     * @see Page.incPageView
     * @param pageId
     * @param emitter 
     */
    public void incPageView(Integer pageId, String emitter)
    {
        Page tmp = pages.get(pageId);
        if(tmp == null)
            System.out.print("page doesnt exist");
        else
            pages.get(pageId).incPageView(emitter);
    }
    
    /**
     * calls deccPageView on the given page
     * @see Page.decPageView
     * @param pageId
     * @param emitter 
     */
    public void decPageView(Integer pageId, String emitter)
    {
        Page tmp = pages.get(pageId);
        if(tmp == null)
            System.out.print("page doesnt exist");
        else
            pages.get(pageId).decPageView(emitter);
    }
    
    public void refactorShapeId(Integer pageId, long newId, long oldId) {
        pages.get(pageId).refactorShapeId(newId, oldId);
    }
    
    /**
     * set the last message id to know who has the most recent version of a file
     * @param messageId the last message id
     * @param emitter the one who send the message
     */
    public void setLastMessageId(Integer messageId, String emitter)
    {
        lastMessage = messageId;
        lastemitter = emitter;
    }

    public Integer getLastMessage() {
        return lastMessage;
    }

    public Stack<Page> getWaitingPages() {
        return waitingPages;
    }
    
    public long getNextId() {
        nextId++;
        return nextId;
    }
            
    @Override
    public String toString()
    {
        String ret = "pages\n";
        for(Integer  key: pages.keySet())
        {
            ret += "key : " + key + " page : " + pages.get(key).toString() + "\n";
        }
        return ret;
    }
    
    public void clear() {
        pages.clear();
        waitingPages.clear();
    }

    public boolean isPrimitiveFilled() {
            return primitiveFilled;
    }

    public void setPrimitiveFilled(boolean primitiveFilled) {
            this.primitiveFilled = primitiveFilled;
    }
    
    public String getFreeNumber() {
        Integer max = new Integer(0);
        for(Integer current : pages.keySet())
        {
            if (current > max)
            {
                max = current;
            }
        }
        max++;
        return max.toString();
    }

    void clearViewers() {
        for(Page page : pages.values())
        {
            page.clearViewers();
        }
    }
}
